package e3dcs

import (
	"fmt"
	"reflect"
	"regexp"
	"runtime"
	"strings"

	"gitee.com/ameise84/e3dcs/internal/log"
	"gitee.com/ameise84/e3utils/errors"
)

func RegisterProtoHandler[T any](a any, mp *map[string]T) {
	v := reflect.ValueOf(a)
	t := reflect.TypeOf(a)

	var method T
	switch t.Kind() {
	case reflect.Ptr, reflect.Struct:
		for {
			for i := 0; i < t.NumMethod(); i++ {
				methodV := v.Method(i)
				methodT := t.Method(i)
				ok, name := parseMethod[T](methodT.Name, methodV, &method)
				if ok {
					if err := registerProtocol[T](name, method, mp); err != nil {
						log.GetLogger().Fatal("register protocol handler").Err(err).Println() //如果是重复注册,原因有可能是Handler的调用没有统一为指针调用或值调用
					}
				} else {
					log.GetLogger().Fatal("invalid method").Strs("func", t.String(), methodT.Name).Println()
				}
			}
			if t.Kind() != reflect.Ptr {
				break
			}
			v = v.Elem()
			t = t.Elem()
		}
	case reflect.Func:
		funcName := getFunctionName(v)
		ok, name := parseMethod[T](funcName, v, &method)
		if ok {
			if err := registerProtocol[T](name, method, mp); err != nil {
				log.GetLogger().Fatal("register protocol handler").Err(err).Println()
			}
		} else {
			log.GetLogger().Fatal("invalid func").Str("func", funcName).Println()
		}
	default:
		log.GetLogger().Fatal("register protocol handler unknown type").Println()
	}
}
func RegisterProtoHandlerWithName(name string, a any, mp *map[string]ProtocolHandler) {
	v := reflect.ValueOf(a)
	t := reflect.TypeOf(a)

	var method ProtocolHandler
	switch t.Kind() {
	case reflect.Func:
		funcName := getFunctionName(v)
		ok, _ := parseMethod(funcName, v, &method)
		if ok {
			if err := registerProtocol(name, method, mp); err != nil {
				log.GetLogger().Fatal("register protocol handler").Err(err).Println()
			}
		} else {
			log.GetLogger().Fatal("invalid func").Str("func", funcName).Println()
		}
	default:
		log.GetLogger().Fatal("register protocol handler unknown type").Println()
	}
}

func getFunctionName(i reflect.Value) string {
	fn := runtime.FuncForPC(i.Pointer()).Name()
	fields := strings.FieldsFunc(fn, func(sep rune) bool {
		if sep == '.' {
			return true
		}
		return false
	})
	if size := len(fields); size > 0 {
		return fields[size-1]
	}
	return ""
}

func checkMethodName(name string) (bool, string) {
	reg := regexp.MustCompile(`^[A-Za-z][A-Za-z0-9]*$`)
	result := reg.FindStringSubmatch(name)
	if result != nil {
		return true, result[0]
	}
	return false, ""
}

func parseMethod[T any](name string, methodV reflect.Value, pf *T) (bool, string) {
	ok, name := checkMethodName(name)
	if ok {
		if v, ok2 := methodV.Interface().(T); ok2 {
			*pf = v
			return true, name
		}
		return false, name
	}
	return false, name
}

func registerProtocol[T any](protocName string, method T, mp *map[string]T) error {
	if protocName == "" {
		return errors.New("protoc name is nil")
	}

	if _, ok := (*mp)[protocName]; ok {
		return errors.New(fmt.Sprintf("protoc name[%s] has been registed", protocName))
	}
	(*mp)[protocName] = method
	log.GetLogger().Trace("register protocol handler").Str("protoc", protocName).Println()
	return nil
}
